﻿using Flurl;
using Flurl.Http;
using Flurl.Http.Configuration;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.WeChat.Configurations;
using SKIT.FlurlHttpClient.Wechat.Api;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace NewRetail.Application.Components.WeChat.Services.HttpClients
{
    #region 微信HttpClientFactory接口
    /// <summary>
    /// 微信HttpClientFactory接口
    /// </summary>
    public interface IWeChatApiHttpClientFactory
    {
        /// <summary>
        /// 创建一个微信httpClient
        /// </summary>
        /// <param name="appId"></param>
        /// <returns></returns>
        WechatApiClient Create(string appId);

        /// <summary>
        /// Get异步请求
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        Task<(byte[], HttpContentHeaders)> GetAsync(string uri);
    }
    #endregion

    #region 微信HttpClientFactory实现
    /// <summary>
    /// 微信HttpClientFactory实现
    /// </summary>
    public partial class WeChatApiHttpClientFactory : IWeChatApiHttpClientFactory
    {
        #region Field
        private readonly System.Net.Http.IHttpClientFactory _httpClientFactory;
        private readonly WeChatOptions _wechatOptions;
        #endregion

        #region Constructor
        public WeChatApiHttpClientFactory(System.Net.Http.IHttpClientFactory httpClientFactory, IOptions<WeChatOptions> wechatOptions)
        {
            _httpClientFactory = httpClientFactory;
            _wechatOptions = wechatOptions.Value;

            FlurlHttp.GlobalSettings.FlurlClientFactory = new DelegatingFlurlClientFactory(_httpClientFactory);
        }
        #endregion

        #region method

        #region 创建一个微信httpClient
        /// <summary>
        /// 创建一个微信httpClient
        /// </summary>
        /// <param name="appId"></param>
        /// <returns></returns>
        public WechatApiClient Create(string appId)
        {
            // NOTICE:
            //   这里的工厂方法是为了演示多租户而存在的，可根据 AppId 生成不同的 API 客户端。
            //   如果你的项目只存在唯一一个租户，那么直接注入 `WechatApiClient` 即可。

            var wechatAccount = _wechatOptions.Accounts?.FirstOrDefault(e => string.Equals(appId, e.AppId));
            if (wechatAccount == null)
                throw new Exception("未在配置项中找到该 AppId 对应的微信账号。");

            return new WechatApiClient(new WechatApiClientOptions()
            {
                AppId = wechatAccount.AppId,
                AppSecret = wechatAccount.AppSecret,
                PushToken = _wechatOptions.CallbackToken
            });
        }

        #endregion

        #region Get请求
        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public async Task<(byte[], HttpContentHeaders)> GetAsync(string uri)
        {
            HttpResponseMessage message = null;
            HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get, uri);
            message = await _httpClientFactory.CreateClient().SendAsync(msg);
            return (message.Content.ReadAsByteArrayAsync().Result, message.Content.Headers);
        }
        #endregion

        #endregion
    }
    #endregion

    #region 委托
    /// <summary>
    /// 委托
    /// </summary>
    public partial class WeChatApiHttpClientFactory
    {
        internal class DelegatingFlurlClientFactory : IFlurlClientFactory
        {
            private readonly System.Net.Http.IHttpClientFactory _httpClientFactory;
            public DelegatingFlurlClientFactory(System.Net.Http.IHttpClientFactory httpClientFactory)
            {
                _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
            }

            public IFlurlClient Get(Url url)
            {
                return new FlurlClient(_httpClientFactory.CreateClient(url.ToUri().Host));
            }

            public void Dispose()
            {
                // Do Nothing
            }
        }
    }
    #endregion
}
